package com.itheima.springbootmybatislilingguo.aspect;

import com.itheima.springbootmybatislilingguo.annotation.MyControllerLog;
import com.itheima.springbootmybatislilingguo.config.RabbitMQConfig;
import com.itheima.springbootmybatislilingguo.domain.LogInfo;
import com.itheima.springbootmybatislilingguo.service.LogInfoService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class ControllerLogAspect {

    private static final Logger logger = LoggerFactory.getLogger(ControllerLogAspect.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private HttpServletRequest request;

    /**
     * 配置切点
     */
    @Pointcut("execution(public * com.itheima.springbootmybatislilingguo.controller.*.*(..))")
    public void controllerLog() {}

    @Around("controllerLog()")
    public Object aroundController(ProceedingJoinPoint pjp) {
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        // 获取方法对象
        Method method = methodSignature.getMethod();
        // 获取方法上的日志注解
        MyControllerLog anno = method.getAnnotation(MyControllerLog.class);
        Object proceed;
        long start = 0;
        long end = 0;
        // 执行方法
        try {
            start = System.currentTimeMillis();
            proceed = pjp.proceed();
            end = System.currentTimeMillis();
            return proceed;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            end = System.currentTimeMillis();
            return null;
        } finally {
            // 日志对象
            LogInfo logInfo = new LogInfo();
            // 获取操作者
//            org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//            String username = null;
//            if (user != null) {
//                username = user.getUsername();
//            }
//            logInfo.setOperator(username);
            // 操作时间
            String curDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            logInfo.setOperatorTime(curDate);
            // IP
            String ip = this.getIP(request);
            logInfo.setOperatorIp(ip);
            // 地址
            logInfo.setOperatorUrl(request.getRequestURI());
            // 执行时长
            logInfo.setImplementTime(end - start);
            // 全限定类名
            logInfo.setClassName(pjp.getTarget().getClass().getName());
            // 方法名
            logInfo.setMethodName(method.getName());
            // 方法参数
            logInfo.setMethodParameter(Arrays.toString(pjp.getArgs()));

            logger.info(logInfo.toString());
            if (anno != null) {
                boolean needResponse = anno.needResponse();
                if (!needResponse) {
                    // 发送消息
//                    rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "boot.log", logInfo);
                    rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "boot.log", "hello world", new MessagePostProcessor() {
                        @Override
                        public Message postProcessMessage(Message message) throws AmqpException {
                            message.getMessageProperties().setExpiration("12000");
                            return message;
                        }
                    });
                }
            }
        }
    }

    private String getIP(HttpServletRequest request) {
        // 操作者IP
        String ip = null;

        //X-Forwarded-For：Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP：apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP：weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP：有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP：nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

}
